package com.google.code.jholidays.core;

import java.io.File;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.List;

import com.google.code.jholidays.events.IEvent;
import com.google.code.jholidays.events.IFactory;
import com.google.code.jholidays.plugins.utils.Reflector;

/**
 * Represents manager which is responsible for loading plugins from specified
 * path.
 * <p>
 * Each plugin is considered to be the JAR file that is put into specified path
 * (plugins lookup directory). JAR file must include both {@link IFactory} and
 * {@link IEvent} implementations.
 * 
 * @author tillias
 * 
 */
public class PluginManager {

    /**
     * Creates new instance of plugin manager using specified plugins lookup
     * path
     */
    public PluginManager() {
	reflectorHelper = new Reflector();
    }

    /**
     * Looks through all JAR files in given directory, and creates instances of
     * any class in those JARs implementing {@link IFactory} interface
     * 
     * @param pluginsPath
     *            JAR files path
     * @return List of instances of all classes implementing {@link IFactory}
     *         interface
     */
    public List<IFactory> getFactories(String pluginsPath) {
	List<IFactory> result = null;

	try {
	    List<File> jarFiles = reflectorHelper.getJarFiles(pluginsPath);
	    result = processJarFiles(jarFiles);
	} catch (Exception e) {
	    // nothing todo here
	}

	return result;
    }

    private List<IFactory> processJarFiles(List<File> jarFiles) {
	List<IFactory> result = new ArrayList<IFactory>();

	if (jarFiles != null && jarFiles.size() > 0) {
	    for (File f : jarFiles) {
		try {
		    URLClassLoader loader = createClassLoader(f);

		    List<IFactory> factories = getFactoriesImpl(f, loader);
		    result.addAll(factories);
		} catch (Exception e) {
		    // nothing todo here
		}
	    }
	}

	return result;
    }

    private List<IFactory> getFactoriesImpl(File f, URLClassLoader loader) {
	List<IFactory> result = new ArrayList<IFactory>();

	if (loader != null) {
	    List<String> classNames = reflectorHelper.getClassNames(f);

	    for (String className : classNames) {
		try {
		    Class<?> cl = loader.loadClass(className);
		    if (reflectorHelper.implementsInterface(cl, IFactory.class)) {
			IFactory instance = (IFactory) cl.newInstance();
			result.add(instance);
		    }
		} catch (Exception e) {
		    // nothing todo here
		}

	    }
	}

	return result;
    }

    private URLClassLoader createClassLoader(File f) {
	URL url = null;
	URLClassLoader loader = null;

	try {
	    url = f.toURI().toURL();
	} catch (Exception e) {
	    // nothing todo here
	}

	if (url != null) {
	    loader = new URLClassLoader(new URL[] { url });
	}

	return loader;
    }

    Reflector reflectorHelper;
}
